package com.example.quartz;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mapper.TJobMapper;
import com.example.util.InvokeUtil;
import com.example.util.TimeHWUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TJobServiceImpl extends ServiceImpl<TJobMapper, TJob> implements TJobService {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
    @Autowired
    private TJobMapper jobMapper;

    /**
     * 初始化定时任务
     */
    @PostConstruct
    public void init() {
        //获取调度器
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //获取所有定时任务
        List<TJob> jobList = this.list(new QueryWrapper<TJob>().eq("status",true));
        //定时任务不存在
        if (jobList == null || jobList.size() <= 0) {
            return;
        }
        //获取有效的定时任务
        jobList = jobList.stream().filter(x -> x.getStatus()).collect(Collectors.toList());
        //没有需要创建的定时任务
        if (jobList == null || jobList.size() <= 0) {
            return;
        }
        try {
            //清空调动任务
            scheduler.clear();
            for (TJob job : jobList) {
                createJob(job);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建定时任务
     *
     * @param job       定时任务
     */
    @Override
    public void createJob(TJob job) throws Exception {
        if (job == null) {
            return;
        }
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //触发器主键
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId() + "", null);
        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        //定时任务主键
        JobKey jobKey = JobKey.jobKey(job.getJobId() + "", null);
        // 构建job信息
        JobDetail jobDetail = JobBuilder.newJob(QuartJob.class).withIdentity(jobKey).build();
        //触发器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
        // 放入参数，运行时的方法可以获取
        jobDetail.getJobDataMap().put("job", job);
        // 判断定时任务存在
        if (scheduler.checkExists(jobKey)) {
            // 定时任务已存在则重新设置触发器
            scheduler.rescheduleJob(triggerKey, cronTrigger);
        } else {
            // 定时任务不存在则创建定时任务
            try {
                scheduler.scheduleJob(jobDetail, cronTrigger);
            } catch (SchedulerException e) {
                TJobServiceImpl.log.warn("定时任务：{}已超过时间，立即执行！", jobDetail.getJobDataMap().get("job"));
                try {
                    InvokeUtil.invokeMethod(job);
                    job.setStatus(false);
                    this.updateById(job);
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    }

    @Override
    public void removeJob(TJob tJob) {
        this.removeById(tJob.getJobId());
        //通过JobName以及JobGroup获得JobKey
        JobKey jobKey = JobKey.jobKey(tJob.getJobId()+"", null);
        try {
            schedulerFactoryBean.getScheduler().deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void addJob(String jobName, Date startTime, String methodName, String params) throws Exception {
        TJob job = new TJob();
        job.setJobName(jobName);
        job.setCronExpression(TimeHWUtil.getCron(startTime));
        job.setExecuteTarget(methodName + params);
        job.setStatus(true);
        this.save(job);
        createJob(job);
        TJobServiceImpl.log.info(jobName + "定时任务设置成功！");
    }
}